/**
 *@file complete.c
 *@brief
 */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/types.h>
#include "complete.h"

static int complete_major=0,complete_minor=0;
//module_param(complete_major,S_IRUGO);
//module_param(complete_minor,S_IRGUO);
struct cdev *complete_cdev;

DECLARE_COMPLETION(completion)

ssize_t complete_read(struct file *filp,char __usr *buf,size_t count,loff_t *f_pos)
{
  unsigned long pos=*f_pos;

  db_printf("info@file %s line %d:Process going to sleep.\n",__FILE__,__LINE__);
  wait_for_completion(&completion);
  db_printf("info@file %s line %d:Process wake up.\n",__FILE__,__LINE__);

  return 0;
}

ssize_t complete_write(struct file *filp,char __usr *buf,size_t count,loff_t *f_pos)
{
  unsigned long pos=*f_pos;

  db_printf("info@file %s line %d:Process will awaking the reader.\n",__FILE__,__LINE__);
  complete(&completion);

  return count;
}

struct file_operations complete_op{
  .owner=THIS_MODULE;
  .read=complete_read;
  .write=complete_write;
}

int complete_init(void)
{
  dev_t dev_no;
  int ret;

  if(complete_major){
    dev_no=MKDEV(complete_major,complete_minor);
    ret=register_chrdev_region(dev_no,1,"complet");
  }
  else{
    ret=alloc_chrdev_region(&dev_no,complete_minor,1,"complete");
    complete_major=MAJOR(dev_no);
  }
  if(ret<0){
    db_printf("err@file %s line %d\n",__FILE__,__LINE__);
  }

  complete_cdev=kmalloc(sizeof(struct cdev),GFP_KERNEL);
  if(!complete_cdev){
    db_printf("err@file %s line %d\n",__FILE__,__LINE__);
    goto fail;
  }
  cdev_init(complete_cdev,&complete_op);
  complete_cdev->owner=THIS_MODULE;
  ret=cdev_add(complete_cdev,dev_no,1);
  if(ret)
    db_printf("err@file %s line %d\n",__FILE__,__LINE__);

  return 0;
 fail:
  complete_cleanup();
  return ret;
}

int complete_cleanup()
{
  dev_t dev_no;

  dev_no=MKDEV(complete_major,complete_minor);
  if(complete_cdev){
    cdev_del(complete_cdev);
    kfree(complete_cdev);
  }
  unregister_chrdev_region(dev_no,1);

}

module_init(complete_init);
module_cleanup(complete_cleanup);

MODULE_AUTHOR("Allon.J");
MODULE_LICENSE("DUAL BSD/GPL");
